// 版权声明，Epic Games 公司保留所有权利

#pragma once

#include "Components/ActorComponent.h"
#include "Net/Serialization/FastArraySerializer.h"

#include "LyraInventoryManagerComponent.generated.h"

#define UE_API LYRAGAME_API

class ULyraInventoryItemDefinition;
class ULyraInventoryItemInstance;
class ULyraInventoryManagerComponent;
class UObject;
struct FFrame;
struct FLyraInventoryList;
struct FNetDeltaSerializeInfo;
struct FReplicationFlags;

/**
 * 库存变化消息结构体
 */
USTRUCT(BlueprintType)
struct FLyraInventoryChangeMessage
{
	GENERATED_BODY()

	//@TODO: 基于标签的库存名称和拥有者Actor，而不是直接暴露组件？
	UPROPERTY(BlueprintReadOnly, Category=Inventory)
	TObjectPtr<UActorComponent> InventoryOwner = nullptr; // 库存拥有者组件

	UPROPERTY(BlueprintReadOnly, Category = Inventory)
	TObjectPtr<ULyraInventoryItemInstance> Instance = nullptr; // 物品实例

	UPROPERTY(BlueprintReadOnly, Category=Inventory)
	int32 NewCount = 0; // 新数量

	UPROPERTY(BlueprintReadOnly, Category=Inventory)
	int32 Delta = 0; // 变化量
};

/**
 * 库存条目结构体
 */
USTRUCT(BlueprintType)
struct FLyraInventoryEntry : public FFastArraySerializerItem
{
	GENERATED_BODY()

	FLyraInventoryEntry()
	{}

	/**
	 * 获取调试字符串
	 * @return 调试字符串
	 */
	FString GetDebugString() const;

private:
	friend FLyraInventoryList;
	friend ULyraInventoryManagerComponent;

	UPROPERTY()
	TObjectPtr<ULyraInventoryItemInstance> Instance = nullptr; // 物品实例

	UPROPERTY()
	int32 StackCount = 0; // 堆叠数量

	UPROPERTY(NotReplicated)
	int32 LastObservedCount = INDEX_NONE; // 最后观察到的数量
};

/**
 * 库存列表结构体
 */
USTRUCT(BlueprintType)
struct FLyraInventoryList : public FFastArraySerializer
{
	GENERATED_BODY()

	FLyraInventoryList()
		: OwnerComponent(nullptr)
	{
	}

	FLyraInventoryList(UActorComponent* InOwnerComponent)
		: OwnerComponent(InOwnerComponent)
	{
	}

	/**
	 * 获取所有物品
	 * @return 物品实例数组
	 */
	TArray<ULyraInventoryItemInstance*> GetAllItems() const;

public:
	//~FFastArraySerializer 契约
	void PreReplicatedRemove(const TArrayView<int32> RemovedIndices, int32 FinalSize); // 复制移除前
	void PostReplicatedAdd(const TArrayView<int32> AddedIndices, int32 FinalSize); // 复制添加后
	void PostReplicatedChange(const TArrayView<int32> ChangedIndices, int32 FinalSize); // 复制变化后
	//~FFastArraySerializer 契约结束

	/**
	 * 网络增量序列化
	 * @param DeltaParms 增量序列化信息
	 * @return 是否成功
	 */
	bool NetDeltaSerialize(FNetDeltaSerializeInfo& DeltaParms)
	{
		return FFastArraySerializer::FastArrayDeltaSerialize<FLyraInventoryEntry, FLyraInventoryList>(Entries, DeltaParms, *this);
	}

	/**
	 * 添加条目（通过物品定义类）
	 * @param ItemClass 物品定义类
	 * @param StackCount 堆叠数量
	 * @return 创建的物品实例
	 */
	ULyraInventoryItemInstance* AddEntry(TSubclassOf<ULyraInventoryItemDefinition> ItemClass, int32 StackCount);

	/**
	 * 添加条目（通过物品实例）
	 * @param Instance 物品实例
	 */
	void AddEntry(ULyraInventoryItemInstance* Instance);

	/**
	 * 移除条目
	 * @param Instance 物品实例
	 */
	void RemoveEntry(ULyraInventoryItemInstance* Instance);

private:
	/**
	 * 广播变化消息
	 * @param Entry 库存条目
	 * @param OldCount 旧数量
	 * @param NewCount 新数量
	 */
	void BroadcastChangeMessage(FLyraInventoryEntry& Entry, int32 OldCount, int32 NewCount);

private:
	friend ULyraInventoryManagerComponent;

private:
	UPROPERTY()
	TArray<FLyraInventoryEntry> Entries; // 条目数组

	UPROPERTY(NotReplicated)
	TObjectPtr<UActorComponent> OwnerComponent; // 拥有者组件
};

/**
 * 结构体操作类型特性特化
 */
template<>
struct TStructOpsTypeTraits<FLyraInventoryList> : public TStructOpsTypeTraitsBase2<FLyraInventoryList>
{
	enum { WithNetDeltaSerializer = true }; // 支持网络增量序列化
};

/**
 * 库存管理组件
 */
UCLASS(MinimalAPI, BlueprintType)
class ULyraInventoryManagerComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UE_API ULyraInventoryManagerComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get()); // 构造函数

	/**
	 * 检查是否可以添加物品定义
	 * @param ItemDef 物品定义类
	 * @param StackCount 堆叠数量
	 * @return 是否可以添加
	 */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Inventory)
	UE_API bool CanAddItemDefinition(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, int32 StackCount = 1);

	/**
	 * 添加物品定义
	 * @param ItemDef 物品定义类
	 * @param StackCount 堆叠数量
	 * @return 创建的物品实例
	 */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Inventory)
	UE_API ULyraInventoryItemInstance* AddItemDefinition(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, int32 StackCount = 1);

	/**
	 * 添加物品实例
	 * @param ItemInstance 物品实例
	 */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Inventory)
	UE_API void AddItemInstance(ULyraInventoryItemInstance* ItemInstance);

	/**
	 * 移除物品实例
	 * @param ItemInstance 物品实例
	 */
	UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category=Inventory)
	UE_API void RemoveItemInstance(ULyraInventoryItemInstance* ItemInstance);

	/**
	 * 获取所有物品
	 * @return 物品实例数组
	 */
	UFUNCTION(BlueprintCallable, Category=Inventory, BlueprintPure=false)
	UE_API TArray<ULyraInventoryItemInstance*> GetAllItems() const;

	/**
	 * 根据定义查找第一个物品堆栈
	 * @param ItemDef 物品定义类
	 * @return 找到的物品实例
	 */
	UFUNCTION(BlueprintCallable, Category=Inventory, BlueprintPure)
	UE_API ULyraInventoryItemInstance* FindFirstItemStackByDefinition(TSubclassOf<ULyraInventoryItemDefinition> ItemDef) const;

	UE_API int32 GetTotalItemCountByDefinition(TSubclassOf<ULyraInventoryItemDefinition> ItemDef) const; // 根据定义获取物品总数量
	UE_API bool ConsumeItemsByDefinition(TSubclassOf<ULyraInventoryItemDefinition> ItemDef, int32 NumToConsume); // 根据定义消耗物品

	//~UObject 接口
	UE_API virtual bool ReplicateSubobjects(class UActorChannel* Channel, class FOutBunch* Bunch, FReplicationFlags* RepFlags) override; // 复制子对象
	UE_API virtual void ReadyForReplication() override; // 准备复制
	//~UObject 接口结束

private:
	UPROPERTY(Replicated)
	FLyraInventoryList InventoryList; // 库存列表
};

#undef UE_API